package cn.izeno.wx.service

import cn.izeno.retrofit2.converter.string.StringConverterFactory
import cn.izeno.wx.WxException
import cn.izeno.wx.models.ErrorCode
import cn.izeno.wx.models.web.WebWxLoginRes
import com.alibaba.fastjson.JSON
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import org.slf4j.LoggerFactory
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.fastjson.FastJsonConverterFactory
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.X509TrustManager


object WX {
  private val logger = LoggerFactory.getLogger(this::class.java)

  var EXCLUDE_ERROR = arrayListOf(
      ErrorCode.ERROR_00000,
      ErrorCode.ERROR_89247,
      ErrorCode.ERROR_89250,
      ErrorCode.ERROR_89251,
      ErrorCode.ERROR_89252,
      ErrorCode.ERROR_89253
  )


  /**
   * 开放平台接口
   */
  val open: ComponentService

  val mini: MiniProgramService

  /**
   * 客服，模板消息接口
   */
  val customer: CustomerService

  /**
   * 自定义菜单接口
   */
  val menu: MenuService

  /**
   * 公众号其他接口
   */
  val mp: MpService

  init {
    val retrofit = Retrofit.Builder().baseUrl("https://login.weixin.qq.com/")
        .client(client())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.createSynchronous())
        .addConverterFactory(StringConverterFactory.create())
        .addConverterFactory(FastJsonConverterFactory.create())
        .build()

    open = retrofit.create(ComponentService::class.java)
    customer = retrofit.create(CustomerService::class.java)
    menu = retrofit.create(MenuService::class.java)
    mp = retrofit.create(MpService::class.java)
    mini = retrofit.create(MiniProgramService::class.java)
  }


  private fun client(): OkHttpClient {
    //  忽略ssl 错误
    val trustManager = object : X509TrustManager {
      override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
      override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
      override fun getAcceptedIssuers(): Array<X509Certificate> {
        return emptyArray()
      }
    }

    val ssl = SSLContext.getInstance("SSL")
    ssl.init(null, arrayOf(trustManager), SecureRandom())

    return OkHttpClient.Builder()
        // 请求
        .readTimeout(1, TimeUnit.MINUTES)
        .addInterceptor { chain ->
          val request = chain.request()

          var res = chain.proceed(request)
          var content = ""

          res.body()?.use {
            content = it.string()
            logger.info("\n[${request.method()}] ${request.url()}\n$content")

            // 微信开放平台接口错误
            val json = JSON.parseObject(content)
            val errCode = json.getIntValue("errcode")
            if (errCode !in EXCLUDE_ERROR.map { errorCode -> errorCode.code }) {
              val errMsg = json.getString("errmsg").split(" hint:").first()
              throw WxException(errCode, errMsg)
            }

            res = res.newBuilder().body(ResponseBody.create(null, content)).build()
          }

          if (content.isNotEmpty() && res.code() == 301) {
            res = res.newBuilder().code(200).build()
          }

          res
        }
        .sslSocketFactory(ssl.socketFactory, trustManager)
        .build()
  }

  private fun parseWebWxLoginResult(raw: String): WebWxLoginRes {
    val result = WebWxLoginRes()
    raw.replace(Regex("[ '\";\r\n]"), "").split("window.")
        .filter { kv -> kv.isNotEmpty() }.map { item ->
          val kv = item.split('=', limit = 2)
          Pair(kv[0], kv[1])
        }.forEach { kv ->
          when (kv.first) {
            "code" -> result.code = kv.second.toLong()
            "redirect_uri" -> result.redirectUrl = kv.second
            "userAvatar" -> result.avatar = kv.second
          }
        }

    return result
  }

}
